/*
 * Created on 29/mag/07
 *
 * To change the template for this generated file go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
package it.unibo.deis.lia.networkInterface;

import java.io.*;
import java.util.Vector;

import org.apache.log4j.Logger;
import org.apache.log4j.net.SocketAppender;

import it.unibo.deis.lia.location.*;

public class Bluetooth extends GenericNetworkInterface{// implements Runnable{
	
	private Vector<RemoteBluetooth> remoteDevices=new Vector<RemoteBluetooth>();
	private boolean activeMonitoring=false;
	private boolean connectorRole=false;
	private String connectorRoleIP;
	
	
	
	private boolean testing=Properties.testing;
	
	private boolean logging=Properties.logging; // true==>performance gathering mode
	private Vector<Location> allowedMACs; // allowed remote interfaces
	Logger logger=Logger.getRootLogger();
	
	private boolean debug=false;
	
//	private ConnectionObserver connObserver;
	
	public Bluetooth() throws Exception{
		this(0);
	}
	
	public Bluetooth(int bluetoothInterfaceNumber) throws Exception{
		if(bluetoothInterfaceNumber>=0){
			Vector<GenericNetworkInterface> interfaces=GenericNetworkInterface.getInterfaces();//getMacAddress();
			if(interfaces.size()==0)throw new Exception("There are no network interfaces");
			for(int i=0;i<interfaces.size()/*&&wirelessCount<=wirelessInterfaceNumber*/;i++){
				if(!isBluetooth(interfaces.elementAt(i))){
					//System.out.println(interfaces.elementAt(i)+" is NOT wireless ");
					interfaces.removeElementAt(i);
					i--;
				}
			}
			if(interfaces.size()<=bluetoothInterfaceNumber)throw new Exception("Interface "+bluetoothInterfaceNumber+" does not exist or is not Bluetooth");
			
			//super.number=interfaces.elementAt(bluetoothInterfaceNumber).number;
			super.hardwareAddress=interfaces.elementAt(bluetoothInterfaceNumber).hardwareAddress;
			super.name=interfaces.elementAt(bluetoothInterfaceNumber).name;
			super.description=interfaces.elementAt(bluetoothInterfaceNumber).description;
		}
		else{
			throw new Exception("Wrong interface number: "+bluetoothInterfaceNumber);
		}
		
		if(logging){
			logger.addAppender(new SocketAppender(Properties.ipLoggerServer,4545));
		}
		if(testing){
			allowedMACs=new Vector<Location>();
			allowedMACs.addElement(new Location("000f3d39c0b2")); // D-Link dbt-120
			allowedMACs.addElement(new Location("000a3a719819")); // Belkin 2.0 EDR
			allowedMACs.addElement(new Location("000b0d609863")); // mopogo a)
			allowedMACs.addElement(new Location("000b0d60aeda")); // mopogo b)
			allowedMACs.addElement(new Location("000b0d609866")); // mopogo c)
			allowedMACs.addElement(new Location("000b0d609860")); // mopogo d)
			allowedMACs.addElement(new Location("000b0d609863")); // mopogo e)
			allowedMACs.addElement(new Location("000b0d60aebe")); // mopogo f)
			//allowedMACs.addElement(new Location("000b0d4b73c4")); // mopogo d)
			allowedMACs.addElement(new Location("0010c6648d77")); // mini-dell
			allowedMACs.addElement(new Location("0015afff5b3c"));  //mio eee
			allowedMACs.addElement(new Location("001060e222d2")); // sitecom matteo
			allowedMACs.addElement(new Location("00076170384b")); // logitech robby
			allowedMACs.addElement(new Location("00037a9591a4")); // toshiba mone
			allowedMACs.addElement(new Location("001BDC0FF884")); //giorgio trust micro
			allowedMACs.addElement(new Location("000B0D301B13"));//giorgio trust grande
			
		}
	}
	
	
	public boolean isConnectorRole(){
		return connectorRole;
	}
	public String getConnectorRoleIP() {
		return connectorRoleIP;
	}

	//connectorRoleIP sono i primi 2 byte dell'indirizzo ip, che sono
	//usati come parte fissa dell'indirizzo per tutte le reti bnep che si creano
	public void setConnectorRole(String connectorAddress,String configPath/*GenericNetworkInterface externalInterface*/)throws Exception{
		if(connectorRole==false){
			connectorRoleIP=connectorAddress;
			connectorRole=true;
			notAllowedRemoteBluetooth.add(new RemoteBluetooth(this.hardwareAddress));
		}
		if(System.getProperty("os.name").startsWith("Linux")){
			setConnectorRoleLinux(configPath);
		}
		else if(System.getProperty("os.name").startsWith("Windows")){	
			setConnectorRoleWindows();
		}
		else{
			connectorRole=false;
			throw new Exception("Not supported Operating System");
		}
	}
	private void setConnectorRoleWindows(/*GenericNetworkInterface externalInterface*/)throws Exception{
		throw new Exception("Bluetooth.setConnectorRoleWindows not implemented: externalInterface ");//+externalInterface);
		//return null; //TODO setConnectorRoleWindows
	}
	private void setConnectorRoleLinux(String configPath/*GenericNetworkInterface externalInterface*/)throws Exception{
		// XXX testare setConnectorRoleLinux
		
		class PIScanThread extends Thread{
			boolean ok=true;
			Bluetooth bluetooth;
			PIScanThread(Bluetooth bluetooth){
				this.bluetooth=bluetooth;
				this.bluetooth.stopMonitoringRemoteDevices();
			}
			void stopPIScanThread(){
				System.out.println("Bluetooth.setConnectorRoleLinux.PIScan");
				ok=false;
				bluetooth.startMonitoringRemoteDevices();
			}
			public void run(){
				System.out.println("Bluetooth.setConnectorRoleLinux.PIScan.run started");
				while(ok){
					try{
						//System.out.println("Bluetooth.setConnectorRoleLinux.PIScan.run");
						bluetooth.setPageInquiryScan();
						sleep(2000);
					}
					catch(Exception e){
						e.printStackTrace();
					}
				}
				System.out.println("Bluetooth.setConnectorRoleLinux.PIScan.run finished");
			}
		}
		
		class PeerConnectorThread extends Thread{

			// XXX testare setConnectorRoleLinux
			private Bluetooth bluetooth;
			
			private String configPath;
			//GenericNetworkInterface externalInterface;
			PeerConnectorThread(Bluetooth bluetooth,String configPath/*,GenericNetworkInterface externalInterface*/){
				this.bluetooth=bluetooth;
				
				this.configPath=configPath;
				//this.externalInterface=externalInterface;
			}
			public void run(){
				try{
					/*Runtime.getRuntime().exec("iptables -F");
					Runtime.getRuntime().exec("iptables -t nat -F");
					Runtime.getRuntime().exec("iptables -t mangle -F");
					Runtime.getRuntime().exec("iptables -X");
					
					Runtime.getRuntime().exec("sysctl -w net.ipv4.ip_forward=1");
					Runtime.getRuntime().exec("echo \"1\" > /proc/sys/net/ipv4/ip_dynaddr");*/
					
					//Process h2=
				    Runtime.getRuntime().exec("hciconfig "+bluetooth.getDescription()+" piscan");
					System.out.println("Bluetooth.setConnectorRoleLinux: starting PIScan");
					PIScanThread piScanThread=new PIScanThread(bluetooth);
					piScanThread.start();
					System.out.println("Bluetooth.setConnectorRoleLinux: PIScan started");
					
					//h2.waitFor();
//					FileWriter fw=new FileWriter("./lib/EXTERNAL.txt",false);
//					fw.write(externalInterface.getDescription());
//					fw.close();
					Process k1=Runtime.getRuntime().exec("pand -K");
					k1.waitFor();
					Process k2=Runtime.getRuntime().exec("killall pand");
					k2.waitFor();
					Process k3=Runtime.getRuntime().exec("killall "+DHCPDAEMON);
					k3.waitFor();
					//Process k4=Runtime.getRuntime().exec("hciconfig "+bluetooth.getDescription()+ " noscan");
					//k4.waitFor();
					//System.out.println(connectorRoleIP);
// Giorgio aggiunta del bridge verso pand per avere un unica connessione su bluetooth		con più interfaccie bluetooth è da ripensare più pan???	        
					
					String pan = "pan"+bluetooth.getDescription().charAt(3);
					
					
					Process k5=Runtime.getRuntime().exec("ifconfig "+pan+" down");
					k5.waitFor();
					Process k6=Runtime.getRuntime().exec("brctl delbr "+pan);
					k6.waitFor();
					Process k7=Runtime.getRuntime().exec("brctl addbr "+pan);
					k7.waitFor();
					
					
					
					

					String line;
					Process k8=Runtime.getRuntime().exec("ifconfig "+pan+" "+Bluetooth.this.connectorRoleIP );
					k8.waitFor();
					String configFilename=configPath+"dhcpd.conf";
					makeDhcpdConf(connectorRoleIP,configFilename);
					
                    //un pan0 per ogni interfaccia bluetooth??
					String command2=DHCPDAEMON+" "+pan+" -cf "+configFilename+" -f -d";
					System.out.println("Pan0 setConnectorRole command2: "+command2);
					
					Process p2=
					Runtime.getRuntime().exec(command2);
					String command1="pand -i "+bluetooth.getDescription()
					/*Giorgio Aggiunta -D*/		+" --listen --role GN --nodetach --persist --master -D";//--encrypt";
										System.out.println("Bluetooth setConnectorRoleLinux command1: "+command1);
										Process p1=Runtime.getRuntime().exec(command1);
										//p1.waitFor();
										//InputStream stdoutStream1 = new BufferedInputStream(p1.getInputStream());
										BufferedReader stdoutStream1 = new BufferedReader(new InputStreamReader(p1.getErrorStream()));
										//StringBuffer buffer1= new StringBuffer();
										
										if(logging){
											logger.info("Bluetooth.setConnectorRoleLinux peer connector ready");
										}
					while((line=stdoutStream1.readLine()) != null){
						System.out.println(line);
						if(line.contains("New connection")){
							String[] tokens=line.split(" ");
							//tokens[6] e` il nome della bnep creata
//							String networkName=tokens[6];
//							int networkNum=Integer.parseInt(networkName.substring(4));
//							String localIP=connectorRoleIP+"."+networkNum+".1";
//							System.out.println("connectorRoleIP="+connectorRoleIP);
//							System.out.println("localIP="+localIP);
							
							
							String networkName=tokens[6];
							int networkNum=Integer.parseInt(networkName.substring(4));
							
							String[] tok=connectorRoleIP.split("\\.");
/*da far vedere a carlo*/	//String localIP=tok[0]+"."+tok[1]+"."+networkNum+".1";
							String localIP=tok[0]+"."+tok[1]+"."+tok[2]+"."+(250-networkNum);/*dasistemare*/
							System.out.println("connectorRoleIP="+connectorRoleIP);
							System.out.println("localIP="+localIP);
							
							
							//Associazione bridge alla nuova interfaccia
							Process if2=Runtime.getRuntime().exec("brctl addif "+pan+" "+networkName);
							if2.waitFor(); if2.destroy();
							
							
							Process if1=Runtime.getRuntime().exec("ifconfig "+networkName+" "+localIP);
							if1.waitFor(); if1.destroy();
							
//							String dhcpConfigFilename=configPath+"dhcpd-"+networkName+".conf";
//							
//							makeDhcpdConf(localIP,dhcpConfigFilename);
//							
//							String command2=DHCPDAEMON+" "+networkName+" -cf "+dhcpConfigFilename+" -f -d";
//							System.out.println("command2: "+command2);
//							Runtime.getRuntime().exec(command2);
							
//							if(connObserver!=null)
//	//occhio al pan0
//							connObserver.newConnection(bluetooth,networkName,localIP);//secondo me qui devo mettere il global address e pan0
						}
												
						// piscan mode after each connection
						//Runtime.getRuntime().exec("hciconfig "+bluetooth.getDescription()+" piscan");
					}
					
					piScanThread.stopPIScanThread();
					System.out.println("Bluetooth setConnectorRoleLinux: finish");
				}
				catch(Exception e){
					e.printStackTrace();
				}
			}
		}
		
		new PeerConnectorThread(this,configPath/*,externalInterface*/).start();
	}
	
	public void resetConnectorRole()throws Exception{
		if(System.getProperty("os.name").startsWith("Linux")){
			resetConnectorRoleLinux();
		}
		else if(System.getProperty("os.name").startsWith("Windows")){	
			resetConnectorRoleWindows();
		}
		else{
			throw new Exception("Not supported Operating System");
		}
		connectorRole=false;
	}
	private void resetConnectorRoleWindows()throws Exception{
		throw new Exception("Bluetooth.resetConnectorRoleWindows not implemented: ");
		//return null; //TODO resetConnectorRoleWindows
	}
	private void resetConnectorRoleLinux()throws Exception{
		
		//  testare resetConnectorRoleLinux
		// reset state

		/*Runtime.getRuntime().exec("sysctl -w net.ipv4.ip_forward=0");
		Runtime.getRuntime().exec("echo \"0\" > /proc/sys/net/ipv4/ip_dynaddr");
		
		Process p=Runtime.getRuntime().exec("iptables -F");
		p.waitFor(); p.destroy();
		p=Runtime.getRuntime().exec("iptables -t nat -F");
		p.waitFor(); p.destroy();
		p=Runtime.getRuntime().exec("iptables -t mangle -F");
		p.waitFor(); p.destroy();
		p=Runtime.getRuntime().exec("iptables -X");
		p.waitFor(); p.destroy();*/
		for(int i=0;i<notAllowedRemoteBluetooth.size();i++){
			if(this.hardwareAddress.equalsIgnoreCase(notAllowedRemoteBluetooth.elementAt(i).getId())){
				notAllowedESSIDs.removeElementAt(i);
			i--;}
		}
		
		Process p=Runtime.getRuntime().exec("pand -K");
		p.waitFor(); p.destroy();
		p=Runtime.getRuntime().exec("killall pand");
		p.waitFor(); p.destroy();
		p=Runtime.getRuntime().exec("killall "+DHCPDAEMON);
		p.waitFor(); p.destroy();
	}
	
	public String connect(RemoteBluetooth remoteBluetooth)throws Exception{
		if(System.getProperty("os.name").startsWith("Linux")){
			return connectLinux(remoteBluetooth);
		}
		else if(System.getProperty("os.name").startsWith("Windows")){	
			return connectWindows(remoteBluetooth);
		}
		else{
			throw new Exception("Not supported Operating System");
		}
	}
	private String connectWindows(RemoteBluetooth remoteBluetooth)throws Exception{
		throw new Exception("Bluetooth.connectWindows not implemented: "+remoteBluetooth);
		//return null; //TODO connectWindows
		//connect "persistente"...
	}
	private String connectLinux(RemoteBluetooth remoteBluetooth)throws Exception{
		// TODO creare una seconda versione per DUN (Dial-Up Networking)
		
		System.out.println("Bluetooth connectLinux");
		
		String command0="pand -i "+super.getDescription()+" --list";
		System.out.println("\tcommand0: "+command0);
		Process p0=
		Runtime.getRuntime().exec(command0);
		p0.waitFor();
		//InputStream stdoutStream0 = new BufferedInputStream(p0.getErrorStream());
		InputStream stdoutStream0 = new BufferedInputStream(p0.getInputStream());
		StringBuffer buffer0= new StringBuffer();
		int c0 = stdoutStream0.read();
		while(c0!=-1){
			buffer0.append((char)c0);
			c0 = stdoutStream0.read();
		}
		p0.destroy();
		String outputText0 = buffer0.toString();
		System.out.println("\toutputText0:\n"+outputText0);
		
		String interfaceName=null;
		if(outputText0.contains(remoteBluetooth.getId())){
			// already connected via PAND
			System.out.println("\talready connected via PAND");
			interfaceName=outputText0.split("[ ]")[0];
			//java.net.NetworkInterface ni=java.net.NetworkInterface.getByName(interfaceName);
			//if(ni.getInetAddresses().hasMoreElements())
			//	newIPAddress=ni.getInetAddresses().nextElement().getHostAddress();
		}
		else{
			System.out.println("\tNOT already connected via PAND");
			
			// NAP: private peer-to-peer network
			//String command="pand -i "+super.getDescription()+" -c "+remoteBluetooth.getId()+" -r PANU -d NAP -n";
			// GN: gateway forwarding packets
			notAllowedRemoteBluetooth.add(remoteBluetooth);
			String command1="pand -i "+super.getDescription()+" --connect "+remoteBluetooth.getId()+" --role PANU --service GN --nodetach";// --persist";
			System.out.println("Bluetooth connectLinux command1: "+command1);
			Process p1=
			Runtime.getRuntime().exec(command1);
			p1.waitFor();
			InputStream stdoutStream1 = new BufferedInputStream(p1.getErrorStream());
			//InputStream stdoutStream1 = new BufferedInputStream(p1.getInputStream());
			StringBuffer buffer1= new StringBuffer();
			int c1 = stdoutStream1.read();
			while(c1!=-1){
				buffer1.append((char)c1);
				c1 = stdoutStream1.read();
			}
			p1.destroy();
			String outputText1 = buffer1.toString();
			System.out.println("\toutputText1:\n"+outputText1);
/*piccola pausa*/		Thread.sleep(500);
			// parsifico per scoprire il nome dell'interfaccia
			//String newInterface=null;
			String lines[]=outputText1.split("[\n]");
			String tokens[]=lines[2].split("[ ]");
			//newInterface=tokens[2];
			if (lines[2].contains("failed")) throw new Exception ("Pand connection failed."); 
			interfaceName=tokens[1];
			
			// attendo un attimo affinche' la connessione PAND sia completata...
			Thread.sleep(500);
		}
		System.out.println("\tinterfaceName: "+interfaceName);
		if(logging){
			logger.info("Bluetooth.connect connected "+remoteBluetooth.getId());
		}

		String ipAddress=null;
		String command1="ifconfig "+interfaceName;
		System.out.println("\tcommand1: "+command1);
		Process p1=
		Runtime.getRuntime().exec(command1);
		p1.waitFor();
		InputStream stdoutStream1 = new BufferedInputStream(p1.getInputStream());
		StringBuffer buffer1= new StringBuffer();
		int c1 = stdoutStream1.read();
		while(c1!=-1){
			buffer1.append((char)c1);
			c1 = stdoutStream1.read();
		}
		p1.destroy();
		String outputText1 = buffer1.toString();
		System.out.println("\toutputText1:\n"+outputText1);
		
		if(outputText1.contains("inet addr")){
			String lines[]=outputText1.split("[\n]");
			for(int i=0; i<lines.length && ipAddress==null; i++){
				if(lines[i].contains("inet addr")){
					String[] tokens=lines[i].split("[: ]");
					for(int j=0; j<tokens.length &&  ipAddress==null; j++){
						//System.out.println( "tokens["+j+"] "+tokens[j] );
						if(tokens[j].equals("inet") && tokens[j+1].equals("addr")){
							ipAddress=tokens[j+2];
						}
					}
				}
			}
			System.out.println("dhclient old ipAddress: "+ipAddress);
		}
		else{
			String command4="ps -ea|grep dhclient";
			System.out.println("Bluetooth setConnectorRoleLinux command4: "+command4);
			Process p4=
			Runtime.getRuntime().exec(command4);
			InputStream stdoutStream4 = new BufferedInputStream(p4.getInputStream());
			//InputStream stdoutStream4 = new BufferedInputStream(p4.getErrorStream());
			StringBuffer buffer4= new StringBuffer();
			int c4 = stdoutStream4.read();
			while(c4!=-1){
				buffer4.append((char)c4);
				c4 = stdoutStream4.read();
			}
			p4.destroy();
			String outputText4 = buffer4.toString();
			System.out.println("dhclient outputText4: "+outputText4);
			
			if(outputText4.contains("dhclient")){
				// do nothing!
				// another dhclient is running...
				// TODO maybe synchronize this method...
			}
			else{
				// faccio partire dhclient su quell'interfaccia!
				//String command2="dhclient -1 "+interfaceName;
				String command2=DHCLIENT+" "+interfaceName;
				System.out.println("Bluetooth setConnectorRoleLinux command2: "+command2);
				Process p2=
				Runtime.getRuntime().exec(command2);
				InputStream stdoutStream2 = new BufferedInputStream(p2.getErrorStream());
				StringBuffer buffer2= new StringBuffer();
				int c2 = stdoutStream2.read();
				while(c2!=-1){
					buffer2.append((char)c2);
					c2 = stdoutStream2.read();
				}
				p2.destroy();
				String outputText2 = buffer2.toString();
				System.out.println("dhclient outputText2: "+outputText2);
				
				// recupero il nuovo ip
				ipAddress=null;
				String lines[]=outputText2.split("[\n]");
				for(int i=0;i<lines.length && ipAddress==null;i++){
					if(lines[i].startsWith("bound to")){
						String tokens[]=lines[i].split("[ ]");
						ipAddress=tokens[2];
					}
				}
				System.out.println("dhclient new ipAddress: "+ipAddress);
			}
		}
		if(logging){
			logger.info("Bluetooth.connect channeled "+remoteBluetooth.getId()+" "+ipAddress);
		}
		
		return ipAddress;
	}
	
	
	public void setPageInquiryScan()throws Exception{
		//System.out.println("Bluetooth.setPageInquiryScan");
		if(System.getProperty("os.name").startsWith("Linux")){
			setPageInquiryScanLinux();
		}
		else if(System.getProperty("os.name").startsWith("Windows")){	
			setPageInquiryScanWindows();
		}
		else{
			throw new Exception("Not supported Operating System");
		}
	}
	private void setPageInquiryScanWindows()throws Exception{
		//BTcommand -i ... pscan on
		Process p=Runtime.getRuntime().exec("./lib/BTcommand -i "+super.getDescription()+" pscan on");
		//BTcommand -i ... iscan on  <- non da' errore ma in realta' non funziona
		p.waitFor(); p.destroy();
		p=Runtime.getRuntime().exec("./lib/BTcommand -i "+super.getDescription()+" iscan on");
		p.waitFor(); p.destroy();
		
	}
	private void setPageInquiryScanLinux()throws Exception{
		Process p=
		Runtime.getRuntime().exec("hciconfig "+super.getDescription()+" piscan");
		p.waitFor(); p.destroy();
		
	}
	
	public void setPageScan()throws Exception{
		if(System.getProperty("os.name").startsWith("Linux")){
			setPageScanLinux();
		}
		else if(System.getProperty("os.name").startsWith("Windows")){	
			setPageScanWindows();
		}
		else{
			throw new Exception("Not supported Operating System");
		}
	}
	private void setPageScanWindows()throws Exception{
		//in teoria dovrei prima disabilitare l'eventuale iscan attivo
		Process p=Runtime.getRuntime().exec("./lib/BTcommand -i "+super.getDescription()+" iscan off");
		p.waitFor(); p.destroy();
		// BTcommand -i ... pscan on
		p=Runtime.getRuntime().exec("./lib/BTcommand -i "+super.getDescription()+" pscan on");
		p.waitFor(); p.destroy();
	}
	private void setPageScanLinux()throws Exception{
		Process p=
		Runtime.getRuntime().exec("hciconfig "+super.getDescription()+" pscan");
		p.waitFor(); p.destroy();
	}
	
	public void setNoScan()throws Exception{
		if(System.getProperty("os.name").startsWith("Linux")){
			setNoScanLinux();
		}
		else if(System.getProperty("os.name").startsWith("Windows")){	
			setNoScanWindows();
		}
		else{
			throw new Exception("Not supported Operating System");
		}
	}
	private void setNoScanWindows()throws Exception{
		//BTcommand -i ... iscan off
		Process p=Runtime.getRuntime().exec("./lib/BTcommand -i "+super.getDescription()+" iscan off");
		p.waitFor(); p.destroy();
		//BTcommand -i ... pscan off
		p=Runtime.getRuntime().exec("./lib/BTcommand -i "+super.getDescription()+" pscan off");
		p.waitFor(); p.destroy();
	}
	private void setNoScanLinux()throws Exception{
		Process p=
		Runtime.getRuntime().exec("hciconfig "+super.getDescription()+" noscan");
		p.waitFor(); p.destroy();
	}
	
	public Vector<NamedLocationOss> getRSSIList()throws Exception{
		Vector<RemoteBluetooth> remotes=getRemoteDevices();
		System.out.println("remotes: "+remotes);
		Vector<NamedLocationOss> rssiList=getRSSIList(remotes);
		System.out.println("RSSIList: "+rssiList);
		return rssiList;
	}
	public Vector<NamedLocationOss> getRSSIList(Vector<RemoteBluetooth> remoteDevices)throws Exception{
		Vector<NamedLocationOss> res;
		if(System.getProperty("os.name").startsWith("Linux")){
			res = getRSSIListLinux(remoteDevices);
		}
		else if(System.getProperty("os.name").startsWith("Windows")){	
			res = getRSSIListWindows(remoteDevices);
		}
		else{
			throw new Exception("Not supported Operating System");
		}
		return res;
	}
	private Vector<NamedLocationOss> getRSSIListWindows(Vector<RemoteBluetooth> remoteDevices)throws Exception{
		//connect x vedere quali sono effettivamente raggiungibili...
		Vector<NamedLocationOss> res=new Vector<NamedLocationOss>();
		
		for(int i=0;i<remoteDevices.size();i++){
			try{
				//non persistente
				String command="./lib/BTcommand -i "+super.getDescription()+" connect "+remoteDevices.elementAt(i).getId();
				//System.out.println("command "+command);
				//Process p1 = 
				Process p =Runtime.getRuntime().exec(command);
				//p1.waitFor();
				
				InputStream stdoutStream = new BufferedInputStream(p.getInputStream());
				
				StringBuffer buffer= new StringBuffer();
				int c = stdoutStream.read();
				while(c!=-1){
					buffer.append((char)c);
//					System.out.print(c);
					c = stdoutStream.read();
				}
				String outputText = buffer.toString();
				// p.waitFor();
				p.destroy();
				
				//System.out.println("letto:"+outputText);
				
				// TODO getRSSIListWindows: aggiungere nome bluetooth e testare RemoteBluetooth
				if(outputText.contains("CONNECTED") || 
					outputText.contains("YOUR OPERATING SYSTEM DOES NOT SUPPORT THIS FUNCTION") ){
					//lo aggiungo alla lista anche se la connect non e' supportata dall'OS
					res.addElement(
							//valore null per indicare che in realta' non ho RSSI
							//new LocationOss(remoteDevices.elementAt(i).getId(),null));
							new RemoteBluetooth(remoteDevices.elementAt(i).getId(),null,null));
				}
			}
			catch(Exception ex){
				ex.printStackTrace();
			}
		}
		return res;
	}
	private Vector<NamedLocationOss> getRSSIListLinux(Vector<RemoteBluetooth> remoteDevices)throws Exception{
		Vector<NamedLocationOss> res=new Vector<NamedLocationOss>();
		
		//Vector<RemoteBluetooth> remotes=getRemoteDevices();
		//System.out.println("Bluetooth getRSSIListLinux");
		for(int i=0;i<remoteDevices.size();i++){
			try{
				String command1="hcitool -i "+super.getDescription()+" cc "+remoteDevices.elementAt(i).getId();
				//System.out.println("\tcommand1 "+command1);
				Process p1 = 
				Runtime.getRuntime().exec(command1);
				//System.out.println("\tpost command1 ");
				//p1.waitFor();
				/**/InputStream stdoutStream1 = new BufferedInputStream(p1.getInputStream());
				StringBuffer buffer1= new StringBuffer();
				int c1 = stdoutStream1.read();
				while(c1!=-1){
					buffer1.append((char)c1);
					//System.out.print("\t"+(char)c1);
					c1 = stdoutStream1.read();
				}
				p1.destroy();
				//String outputText1 = buffer1.toString();
				//System.out.println("\toutputText1 "+outputText1);
				/**/
				
				/**/String command2="hcitool -i "+super.getDescription()+" lst "+remoteDevices.elementAt(i).getId() + " 3276";
				//System.out.println("\tcommand2 "+command2);
				Process p2=
				Runtime.getRuntime().exec(command2);// 3276 slots ~ 2s
				//p2.waitFor();
				InputStream stdoutStream2 = new BufferedInputStream(p2.getInputStream());
				StringBuffer buffer2= new StringBuffer();
				int c2 = stdoutStream2.read();
				while(c2!=-1){
					buffer2.append((char)c2);
					c2 = stdoutStream2.read();
				}
				p2.destroy();
				
				//String outputText2 = buffer2.toString();
				//System.out.println("\toutputText2 "+outputText2);
				/**/
				
				String command3="hcitool -i "+super.getDescription()+" rssi "+remoteDevices.elementAt(i).getId();
				//System.out.println("\tcommand3 "+command3);
				Process p3 = Runtime.getRuntime().exec(command3);
				//p3.waitFor();
				InputStream stdoutStream3 = new BufferedInputStream(p3.getInputStream());
				StringBuffer buffer3= new StringBuffer();
				int c3 = stdoutStream3.read();
				while(c3!=-1){
					buffer3.append((char)c3);
					c3 = stdoutStream3.read();
				}
				p3.destroy();
				String outputText3 = buffer3.toString();
				//System.out.println("\toutputText3 "+outputText3);
				
				String rssi=null;
				String[]lines3=outputText3.split("[\n]");
				for(int j=0;j<lines3.length;j++)	{
					//System.out.println("lines3["+j+"] "+lines3[j]);
					String[]tokens=lines3[j].split("[ ]");
					//for(int k=0;k<tokens.length;k++){
					//	System.out.println("tokens["+k+"] "+tokens[k]);
					//}
					if(tokens.length==4){
						/*res.addElement(
								new LocationOss(remoteDevices.elementAt(i).getId(),tokens[3])
							);*/
						rssi=tokens[3];
					}
					else if(debug){
						// only for debug purpose 
						System.out.println("---------- getRSSIListLinux: no rssi! -------------");
						System.out.println("command3: "+command3);
						System.out.println("lines["+j+"] "+lines3[j]);
						for(int k=0;k<tokens.length;k++){
							System.out.println("tokens["+k+"] "+tokens[k]);
						}
					}
				}
				
				/*String command4="hcitool -i "+super.getDescription()+" name "+remoteDevices.elementAt(i).getId();
				System.out.println("\tcommand4 "+command4);
				Process p4 = Runtime.getRuntime().exec(command4);
				//p4.waitFor();
				InputStream stdoutStream4 = new BufferedInputStream(p4.getInputStream());
				StringBuffer buffer4= new StringBuffer();
				int c4 = stdoutStream4.read();
				while(c4!=-1){
					if(c4!='\n'&&c4!='\r'){
						// delete the carriage return
						buffer4.append((char)c4);
					}
					c4 = stdoutStream4.read();
				}
				p4.destroy();
				String outputText4 = buffer4.toString();
				System.out.println("\toutputText4 "+outputText4);
				String name=outputText4;/**/
				
				// delete the carriage return
				/*String name=null;
				if(outputText4.length()>2){
					// at least one character
					name=outputText4.substring(0, outputText4.length()-2);
				}*/
				//System.out.println("Bluetooth: getRSSIListLinux name "+name);
				
				/*String[]lines4=outputText4.split("[\n]");
				for(int j=0;j<lines4.length;j++)	{
					//System.out.println("lines["+j+"] "+lines[j]);
					String[]tokens=lines4[j].split("[ ]");
					for(int k=0;k<tokens.length;k++){
						System.out.println("name: tokens["+k+"] "+tokens[k]);
					}
					if(tokens.length==4){
						res.addElement(
								new LocationOss(remoteDevices.elementAt(i).getId(),tokens[3])
							);
					}
					else if(debug){
						// only for debug purpose 
						System.out.println("---------- getRSSIListLinux: no name! -------------");
						System.out.println("command4: "+command4);
						System.out.println("lines["+j+"] "+lines4[j]);
						for(int l=0;l<tokens.length;l++){
							System.out.println("tokens["+l+"] "+tokens[l]);
						}
					}
				}*/
				
				if(rssi!=null){// && name!=null){
				}
				else{
					System.err.println("Bluetooth getRSSIListLinux: rssi="+rssi+" name="+((RemoteBluetooth)remoteDevices.elementAt(i)).getName());
					rssi="-25"; // XXX in teoria eliminare
				}
				//System.out.println("BLUETOOTH.java: new RemoteBluetooth("+remoteDevices.elementAt(i).getId()+","+((RemoteBluetooth)remoteDevices.elementAt(i)).getName()+","+rssi+")");
				res.addElement( new RemoteBluetooth(remoteDevices.elementAt(i).getId(),((RemoteBluetooth)remoteDevices.elementAt(i)).getName(),rssi) );
			}
			catch(Exception ex){
				ex.printStackTrace();
			}
		}
		return res;
	}
	
	public Vector<NamedLocationOss> getLQList()throws Exception{
		Vector<RemoteBluetooth> remotes=getRemoteDevices();
		Vector<NamedLocationOss> rssiList=getLQList(remotes);
		return rssiList;
	}
	public Vector<NamedLocationOss> getLQList(Vector<RemoteBluetooth> remoteDevices)throws Exception{
		Vector<NamedLocationOss> res;
		if(System.getProperty("os.name").startsWith("Linux")){
			res = getRSSILQLinux(remoteDevices);
		}
		else if(System.getProperty("os.name").startsWith("Windows")){	
			res = getRSSILQWindows(remoteDevices);
		}
		else{
			throw new Exception("Not supported Operating System");
		}
		return res;
	}
	private Vector<NamedLocationOss> getRSSILQWindows(Vector<RemoteBluetooth> remoteDevices)throws Exception{
		//identico a RSSIWindows
		return getRSSIListWindows(remoteDevices);
	}
	private Vector<NamedLocationOss> getRSSILQLinux(Vector<RemoteBluetooth> remoteDevices)throws Exception{
		Vector<NamedLocationOss> res=new Vector<NamedLocationOss>();
		
		//Vector<RemoteBluetooth> remotes=getRemoteDevices();
		for(int i=0;i<remoteDevices.size();i++){
			try{
				String command1="hcitool -i "+super.getDescription()+" cc "+remoteDevices.elementAt(i).getId();
				//System.out.println("command1 "+command1);
				Process p = 
				Runtime.getRuntime().exec(command1);
				p.waitFor(); p.destroy();
				
				//String command2="hcitool -i "+super.getDescription()+" lst "+remoteDevices.elementAt(i).getId() + " 3276";
				String command2="hcitool -i "+super.getDescription()+" lst "+remoteDevices.elementAt(i).getId() + " 1638";
				//System.out.println("command2 "+command2);
				//Process p2=
				p=Runtime.getRuntime().exec(command2);// 3276 slots ~ 2s
				p.waitFor(); p.destroy();
				
				String command3="hcitool -i "+super.getDescription()+" lq "+remoteDevices.elementAt(i).getId();
				//System.out.println("command2 "+command2);
				Process p3 = Runtime.getRuntime().exec(command3);
				//p3.waitFor();
				
				InputStream stdoutStream = new BufferedInputStream(p3.getInputStream());
				StringBuffer buffer= new StringBuffer();
				int c = stdoutStream.read();
				while(c!=-1){
					buffer.append((char)c);
					c = stdoutStream.read();
				}
				p3.destroy();
				String outputText = buffer.toString();
				
				String[]lines=outputText.split("[\n]");
				for(int j=0;j<lines.length;j++)	{
					//System.out.println("lines["+j+"] "+lines[j]);
					String[]tokens=lines[j].split("[ ]");
					//for(int k=0;k<tokens.length;k++){
					//	System.out.println("tokens["+k+"] "+tokens[k]);
					//}
					if(tokens.length==3){
						res.addElement(
								new RemoteBluetooth(remoteDevices.elementAt(i).getId(),tokens[2])
							);
					}
					else{
						// only debug purpose 
						System.out.println("---------- getRSSIListLinux: no lq! -------------");
						System.out.println("command3: "+command3);
						System.out.println("lines["+j+"] "+lines[j]);
						for(int k=0;k<tokens.length;k++){
							System.out.println("tokens["+k+"] "+tokens[k]);
						}
					}
				}
			}
			catch(Exception ex){
				ex.printStackTrace();
			}
		}
		return res;
	}
	
	class RemoteDevicesMonitoring extends Thread{
		public void run(){
			//System.out.println("Bluetooth.run");
			while(activeMonitoring){
				try{
					//System.out.println("Bluetooth.run getRemoteDevices "+System.currentTimeMillis());
					remoteDevices=getSyncRemoteDevices();
					Thread.sleep(1000);
				}
				catch(Exception ex){
					ex.printStackTrace();
				}
			}
			//System.out.println("Bluetooth.run finish");
		}
	}
	public void startMonitoringRemoteDevices(){
		if(!activeMonitoring){
			//Thread t=new Thread(this);
			//t.start();
			activeMonitoring=true;
			new RemoteDevicesMonitoring().start();
		}
	}
	public void stopMonitoringRemoteDevices(){
		activeMonitoring=false;
	}
	public Vector<RemoteBluetooth> getRemoteDevices()throws Exception{
		Vector<RemoteBluetooth> res;
		if(activeMonitoring){
			//System.out.println("Bluetooth.getRemoteDevices true=="+activeMonitoring);
			res=new Vector<RemoteBluetooth>(remoteDevices);
		}
		else{
			//System.out.println("Bluetooth.getRemoteDevices false=="+activeMonitoring);
			res=new Vector<RemoteBluetooth>(getSyncRemoteDevices());
		}
		
		if(testing){
			// delete/neglect remote interfaces not listed in "allowedMACs"
			for(int i=0;i<res.size();i++){
				String mac=res.elementAt(i).getId().toLowerCase().replaceAll(":", "");
				//System.out.println("found "+mac);
				boolean allowed=false;
				for(int j=0;j<allowedMACs.size();j++){
					//System.out.println("\t"+allowedMACs.elementAt(j).getId());
					if(allowedMACs.elementAt(j).getId().equals(mac)){
						//System.out.println("\t"+allowedMACs.elementAt(j).getId());
						allowed=true;
						break;
					}
				}
				if(!allowed){
					//System.out.println("\t\t deleting "+mac);
					res.removeElementAt(i);
					i--;
				}
				//impedisce la connessione ha quelli in lista nera!
				boolean notAllowed=false;
				for(int m=0;m<notAllowedRemoteBluetooth.size();m++){
					if(mac.equalsIgnoreCase(notAllowedRemoteBluetooth.elementAt(m).getId())){
						notAllowed=true;
						}
					
				}
				if(notAllowed){
					res.removeElementAt(i);
					i--;
				}
			}
		}
		
		if(logging){
			for (int i=0;i<res.size();i++){
				logger.info("Bluetooth.getRemoteDevices found "+res.elementAt(i).getId());
			}
		}
		
		return res;
	}
	private Vector<RemoteBluetooth> getSyncRemoteDevices()throws Exception{
		Vector<RemoteBluetooth> remotes;
		if(System.getProperty("os.name").startsWith("Windows")){
			remotes=getRemoteDevicesWindows();
		}
		else if(System.getProperty("os.name").startsWith("Linux")){	
			remotes=getRemoteDevicesLinux();
		}
		else{
			throw new Exception("Not supported Operating System");
		}
		return remotes;
	}
	private Vector<RemoteBluetooth> getRemoteDevicesWindows()throws Exception{
		Vector<RemoteBluetooth> remotes=new Vector<RemoteBluetooth>();
		//inquiry generica con 4*1.28s di timeout
		String command="./lib/BTcommand -i "+super.getHardwareAddress()+" inquiry";
		Process p = Runtime.getRuntime().exec(command);
		//try{
			//p.waitFor();
		//}
		//catch(Exception ex){
		//	ex.printStackTrace();
		//}
		InputStream stdoutStream = new BufferedInputStream(p.getInputStream());
		
		StringBuffer buffer= new StringBuffer();
		int c = stdoutStream.read();
		while(c!=-1){
			buffer.append((char)c);
			c = stdoutStream.read();
		}
		p.destroy();
		String outputText = buffer.toString();
		//System.out.println("getRemoteDevicesLinux outputText\n"+outputText);
		String[]lines=outputText.split("\n");
		for(int i=0;i<lines.length;i++)	{
			if(! (lines[i].contains("Error:"))){
				String[]tokens=lines[i].split("[\t]");
//				for(int j=0;j<tokens.length;j++) System.out.println("tokens["+j+"] "+tokens[j]);
				
				if (tokens.length == 4)
					remotes.addElement(
							new RemoteBluetooth(tokens[1],tokens[2])
						);
			}
		}
		return remotes;
	}
	private Vector<RemoteBluetooth> getRemoteDevicesLinux()throws Exception{
		Vector<RemoteBluetooth> remotes=new Vector<RemoteBluetooth>();
		
		String command="hcitool -i "+super.getDescription()+" scan --flush";
		//String command="hcitool -i "+super.getDescription()+" inq";
		Process p = Runtime.getRuntime().exec(command);
		//System.out.println("command "+command);
		//try{
			//p.waitFor();
		//}
		//catch(Exception ex){
		//	ex.printStackTrace();
		//}
		InputStream stdoutStream = new BufferedInputStream(p.getInputStream());
		 
		StringBuffer buffer= new StringBuffer();
		int c = stdoutStream.read();
		while(c!=-1){
			buffer.append((char)c);
			c = stdoutStream.read();
		}
		p.destroy();
	
		String outputText = buffer.toString();
		//System.out.println("getRemoteDevicesLinux outputText\n"+outputText);
		String[]lines=outputText.split("[\n]");
		for(int i=0;i<lines.length;i++)	{
			if(!lines[i].contains("Scanning")){
			//if(!lines[i].contains("Inquiring")){
				String[]tokens=lines[i].split("[\t]");
				if(tokens.length==3){
					//System.out.println("new RemoteBluetooth("+tokens[1]+","+tokens[2]+")");
					remotes.addElement(
							//new RemoteBluetooth(tokens[1],null)//tokens[2])
							new RemoteBluetooth(tokens[1],tokens[2])
						);
				}
			}
		}
		return remotes;
	}
	
	
	public Vector<RemoteBluetooth> getConnectedDevices()throws Exception{
		Vector<RemoteBluetooth> remotes;
		if(System.getProperty("os.name").startsWith("Windows")){
			remotes=getConnectedDevicesWindows();
		}
		else if(System.getProperty("os.name").startsWith("Linux")){	
			remotes=getConnetedDevicesLinux();
		}
		else{
			throw new Exception("Not supported Operating System");
		}
		return remotes;
	}
	private Vector<RemoteBluetooth> getConnectedDevicesWindows()throws Exception{
		Vector<RemoteBluetooth> remotes=new Vector<RemoteBluetooth>();
		//inquiry minima di 1.28s x soli dispositivi connessi
		String command="./lib/BTcommand -i "+super.getDescription()+" inquiry -c -t 1";
		Process p = Runtime.getRuntime().exec(command);
		//try{
			//p.waitFor();
		//}
		//catch(Exception ex){
		//	ex.printStackTrace();
		//}
		InputStream stdoutStream = new BufferedInputStream(p.getInputStream());
		
		StringBuffer buffer= new StringBuffer();
		int c = stdoutStream.read();
		while(c!=-1){
			buffer.append((char)c);
			c = stdoutStream.read();
		}
		p.destroy();
		String outputText = buffer.toString();
		//System.out.println("getRemoteDevicesLinux outputText\n"+outputText);
		String[]lines=outputText.split("\n");
		for(int i=0;i<lines.length;i++)	{
			if(! (lines[i].contains("Error:"))){
				String[]tokens=lines[i].split("[\t]");
//				for(int j=0;j<tokens.length;j++) System.out.println("tokens["+j+"] "+tokens[j]);
				
				if (tokens.length == 4)
					remotes.addElement(
							new RemoteBluetooth(tokens[1])
						);
			}
		}
		return remotes;
		//BTcommand -i ... inquiry -c -t 1
	}
	private Vector<RemoteBluetooth> getConnetedDevicesLinux()throws Exception{
		Vector<RemoteBluetooth> remotes=new Vector<RemoteBluetooth>();
		
		String command="hcitool -i "+super.getDescription()+" con";
		Process p = Runtime.getRuntime().exec(command);
		//try{
			//p.waitFor();
		//}
		//catch(Exception ex){
		//	ex.printStackTrace();
		//}
		InputStream stdoutStream = new BufferedInputStream(p.getInputStream());
		 
		StringBuffer buffer= new StringBuffer();
		int c = stdoutStream.read();
		while(c!=-1){
			buffer.append((char)c);
			c = stdoutStream.read();
		}
		p.destroy();
		String outputText = buffer.toString();
		//System.out.println("getRemoteDevicesLinux outputText\n"+outputText);
		String[]lines=outputText.split("[\n]");
		for(int i=0;i<lines.length;i++)	{
			if(!lines[i].contains("Connections:")){
				String[]tokens=lines[i].split("[\t ]");
				/*for(int j=0;j<tokens.length;j++){
					System.out.println("tokens["+j+"] "+tokens[j]);
				}*/
				remotes.addElement(new RemoteBluetooth(tokens[3]));
			}
		}
		return remotes;
	}
	
	
	
	public static final boolean isBluetooth(GenericNetworkInterface genericNetworkInterface)throws Exception{
		boolean isBluetooth;
		if(System.getProperty("os.name").startsWith("Windows")){
			isBluetooth=isBluetoothWindows(genericNetworkInterface);
		}
		else if(System.getProperty("os.name").startsWith("Linux")){	
			isBluetooth=isBluetoothLinux(genericNetworkInterface);
		}
		else{
			throw new Exception("Not supported Operating System");
		}
		return isBluetooth;
	}
	private static final boolean isBluetoothWindows(GenericNetworkInterface genericNetworkInterface)throws Exception{
		Process p2 = Runtime.getRuntime().exec("./lib/BTcommand devices");
//		System.out.println("OK");
		InputStream stdoutStream2 = new BufferedInputStream(p2.getInputStream());

		StringBuffer buffer2= new StringBuffer();
		int c2 = stdoutStream2.read();
		while(c2!=-1){
			buffer2.append((char)c2);
			c2 = stdoutStream2.read();
		}
		p2.destroy();
		stdoutStream2.close();

		String btcommandOutput = buffer2.toString();

		String []lines=btcommandOutput.split("\n");
		try {
			//int n=0;
			for(int i=0;i<lines.length;i++){
				if(lines[i].contains(genericNetworkInterface.getDescription()))
					return true;
			}
			
		}
		catch(Exception ex) {
			ex.printStackTrace();	
		}
		return false;
	}
	private static final boolean isBluetoothLinux(GenericNetworkInterface genericNetworkInterface)throws Exception{
		String command="hciconfig";
		Process p = Runtime.getRuntime().exec(command);
		//p.waitFor();
		InputStream stdoutStream = new BufferedInputStream(p.getInputStream());
		 
		StringBuffer buffer= new StringBuffer();
		int c = stdoutStream.read();
		while(c!=-1){
			buffer.append((char)c);
			c = stdoutStream.read();
		}
		p.destroy();
		String outputText = buffer.toString();
		//System.out.println("isWirelessLinux outputText\n"+outputText);
		if(outputText.contains(genericNetworkInterface.getDescription())){
			return true;
		}
		else{
			return false;
		}
	}
	
//	public interface ConnectionObserver{
//		public void newConnection(Bluetooth interf, String networkName, String localAddress);
//	}
//	
//	public void setConnectionObserver(ConnectionObserver observer){
//		connObserver=observer;
//	}
}
